package com.zmj.sy.mom.srv.aps.service.scheduler.inverted;

import com.zmj.sy.mom.srv.aps.bean.entity.order.OrderPhase;
import com.zmj.sy.mom.srv.aps.bean.entity.resource.Phase;
import com.zmj.sy.mom.srv.aps.service.scheduler.order.DefaultOrder;
import com.zmj.sy.mom.srv.aps.service.scheduler.order.DefaultPhase;
import com.zmj.sy.mom.srv.aps.service.scheduler.resource.shift.TimeUtils;
import lombok.Getter;
import lombok.Setter;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.util.*;
import java.util.function.Function;

/**
 * 待排订单信息
 */
@Getter
@Setter
public class InvertedScheduleOrder {

    private List<DefaultOrder> orders;

    private transient List<List<DefaultOrder>> orchestratedOrders;

    /**
     * 获取订单的直接前序订单
     */
    public DefaultOrder previousOrder(InvertedScheduleContext context, DefaultOrder order) {
        if (orchestratedOrders == null) {
            orchestratedOrders = orchestrateOrder(context);
        }
        DefaultOrder found = null;
        for (List<DefaultOrder> orchestratedOrder : orchestratedOrders) {
            for (DefaultOrder value : orchestratedOrder) {
                if (order.getOrder().getId().equals(value.getOrder().getId())) {
                    return found;
                } else {
                    found = value;
                }
            }
        }
        throw new IllegalArgumentException("订单数据异常，" + order.getOrder().getId());
    }

    /**
     * 获取订单的直接后序订单
     */
    public DefaultOrder nextOrder(InvertedScheduleContext context, DefaultOrder order) {
        if (orchestratedOrders == null) {
            orchestratedOrders = orchestrateOrder(context);
        }
        if (order == null) {
            return orchestratedOrders.get(0).get(0);
        }
        boolean found = false;
        for (List<DefaultOrder> orchestratedOrder : orchestratedOrders) {
            for (DefaultOrder value : orchestratedOrder) {
                if (order.getOrder().getId().equals(value.getOrder().getId())) {
                    found = true;
                } else if (found) {
                    return value;
                }
            }
        }
        return null;
    }

    /**
     * 订单编织
     */
    private List<List<DefaultOrder>> orchestrateOrder(InvertedScheduleContext context) {
        List<DefaultOrder> orders = new ArrayList<>(this.orders);
        List<List<DefaultOrder>> result = new ArrayList<>();
        if (context.getRelationship().equals(InvertedScheduleContext.RELATIONSHIP_CONSTRUCTION)) {
            orders.sort(Comparator.comparing((Function<DefaultOrder, String>) o -> o.getOrder().getPlannedMonth())
                    .thenComparing(o -> o.getOrder().getSeq()));
            Map<String, List<DefaultOrder>> orderMap = new HashMap<>();
            for (DefaultOrder order : orders) {
                List<DefaultOrder> orderList = orderMap.computeIfAbsent(order.getOrder().getConstructNo(), k -> {
                    List<DefaultOrder> temp = new ArrayList<>();
                    result.add(temp);
                    return temp;
                });
                orderList.add(order);
            }
            return result;
        }
        throw new IllegalArgumentException("倒排配置错误");
    }

    /**
     * 计算工序实际工时
     */
    public static Duration executeTime(InvertedScheduleResource resource,
                                       DefaultPhase phase) {
        // 不算工时
        if (Arrays.asList("WW", "WL").contains(phase.getPhase().getPhaseCode())) {
            return Duration.ZERO;
        }
        // 工艺工时
        Duration cycleTime = cycleTime(resource, phase);

        // 物流工时
        Duration transferTime = resource.transferTime(phase);

        // 缓存工时
        Duration cacheTime = resource.cacheTime(phase);

        // 其他工时
        Duration otherTime = otherTime(phase);
        return cycleTime
                .plus(transferTime)
                .plus(cacheTime)
                .plus(otherTime);
    }

    private static Duration otherTime(DefaultPhase phase) {
        if (phase.getBom().getParent() != null) {
            List<DefaultPhase> phases = phase.getBom().getPhases();
            if (phases.get(phases.size() - 1).getPhase().getId().equals(phase.getPhase().getId())) {
                List<DefaultPhase> parentPhases = phase.getBom().getParent().getPhases();
                if (parentPhases.stream().anyMatch(p -> p.getPhase().getPhaseCode().contains("PZ") /*|| p.getPhaseCode().contains("PP")*/)) {
                    return Duration.ofHours(8);
                }
            }
        }
        return Duration.ZERO;
    }

    private static Duration cycleTime(InvertedScheduleResource resource,
                                      DefaultPhase phase) {
        OrderPhase orderPhase = phase.getPhase();
        Phase phaseConfig = resource.getFactory().phase(orderPhase.getPhaseCode());
        if (phaseConfig == null) {
            return Duration.ZERO;
        }
        if (Objects.equals(phaseConfig.getFlowTimeType(), 1)) {
            return TimeUtils.time(phaseConfig.getFlowTimeValue(), phaseConfig.getFlowTimeUnit());
        }

        BigDecimal workAbility = resource.workAbility(phase);
        return Duration.ofSeconds(
                new BigDecimal(orderPhase.getWorkTime())
                        .divide(new BigDecimal(60), 7, RoundingMode.UP) // 单件工时分
                        .divide(workAbility, 7, RoundingMode.UP)// 工作能力
                        .divide(new BigDecimal(60), 0, RoundingMode.UP) // 工时小时
                        .multiply(BigDecimal.valueOf(1.2)) // 生产效率 1.2
                        .multiply(new BigDecimal(60)) // 加倍
                        .multiply(new BigDecimal(60)) // 秒
                        .setScale(0, RoundingMode.UP)
                        .intValue()
        );
    }

}
